/**
  ******************************************************************************
  * @file    main.c
	* @author  MCU Software Team
  * @Version V1.2.0
  * @Date    2021-01-11
  * @brief   main function
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"	
#include <stdio.h>
#include "s_task.h"
#include "u8g2.h"

#define SW_IIC 0
#define I2C_SPEED_RATE	100   //uint khz

// M0没有位操作区 
typedef struct {
		uint16_t bit0 : 1;
		uint16_t bit1 : 1;
		uint16_t bit2 : 1;
		uint16_t bit3 : 1;
		uint16_t bit4 : 1;
		uint16_t bit5 : 1;
		uint16_t bit6 : 1;
		uint16_t bit7 : 1;
		uint16_t bit8 : 1;
		uint16_t bit9 : 1;
		uint16_t bit10 : 1;
		uint16_t bit11 : 1;
		uint16_t bit12 : 1;
		uint16_t bit13 : 1;
		uint16_t bit14 : 1;
		uint16_t bit15 : 1;
} Bits_16_TypeDef;


#define PAout(n) ((Bits_16_TypeDef *)(&(GPIOA->ODR)))->bit##n
#define PBout(n) ((Bits_16_TypeDef *)(&(GPIOB->ODR)))->bit##n
#define PCout(n) ((Bits_16_TypeDef *)(&(GPIOC->ODR)))->bit##n
#define PDout(n) ((Bits_16_TypeDef *)(&(GPIOD->ODR)))->bit##n

#define PAin(n) ((Bits_16_TypeDef *)(&(GPIOA->IDR)))->bit##n
#define PBin(n) ((Bits_16_TypeDef *)(&(GPIOB->IDR)))->bit##n
#define PCBin(n) ((Bits_16_TypeDef *)(&(GPIOC->IDR)))->bit##n
#define PDBin(n) ((Bits_16_TypeDef *)(&(GPIOD->IDR)))->bit##n

/* Private variables ---------------------------------------------------------*/
int g_stack0[128 / sizeof(int)];
// int g_stack1[64 / sizeof(int)];

I2C_HandleTypeDef i2c_test = {0};
FlagStatus i2c_int = RESET;
/* Private function prototypes -----------------------------------------------*/
void delay_us(uint32_t time) {
  uint32_t i=8*time;
  while(i--);
}
/* Private user code ---------------------------------------------------------*/
volatile bool g_is_low = false;
volatile bool g_exit = false;

//进度条显示
void DrawProcess(u8g2_t *u8g2)
{
	for(int i=10;i<=80;i=i+2)
	{
		u8g2_ClearBuffer(u8g2); 
		
	    char buff[20];
		sprintf(buff,"%d%%",(int)(i/80.0*100));
		
//		u8g2_SetFont(u8g2,u8g2_font_ncenB18_tf);
//		u8g2_DrawStr(u8g2,32,32,"u8g2");//字符显示
		
		u8g2_SetFont(u8g2,u8g2_font_ncenB08_tf);
		u8g2_DrawStr(u8g2,100,49,buff);//当前进度显示
		
		u8g2_DrawRBox(u8g2,16,40,i,10,4);//圆角填充框矩形框
		u8g2_DrawRFrame(u8g2,16,40,80,10,4);//圆角矩形
	
		u8g2_SendBuffer(u8g2);
	}
}

//画点
void DrawPoint(u8g2_t *u8g2)
{
	uint8_t i=0,j=0;
	
	u8g2_ClearBuffer(u8g2); 
	
	for(j=0;j<64;j=j+8,i=0)
	{
		for(i=0;i<128;i=i+8)
		{
			u8g2_DrawPixel(u8g2,i,j);   			
			u8g2_SendBuffer(u8g2);
		}
	}//8*16  8*8
}

//线条测试
void DrawLine(u8g2_t *u8g2)
{
	u8g2_ClearBuffer(u8g2); 
	for(int i=0;i<20;i++)
	{
		u8g2_DrawLine(u8g2,0,0,i*10,63);
		u8g2_SendBuffer(u8g2);
	}
	
	for(int i=0;i<20;i++)
	{
		u8g2_DrawLine(u8g2,128,0,128-i*10,63);
		u8g2_SendBuffer(u8g2);
	}
}

//矩形测试
void DrawBox(u8g2_t *u8g2)
{
	u8g2_ClearBuffer(u8g2);
	for(int i=0;i<31;i+=2)
	{
		u8g2_DrawFrame(u8g2,i*2,i,128-i*4,64-2*i);
		u8g2_SendBuffer(u8g2);
	}
	
	u8g2_ClearBuffer(u8g2);
	for(int i=0;i<31;i+=2)
	{
		u8g2_DrawRFrame(u8g2,i*2,i,128-i*4,64-2*i,10-i/3);
		u8g2_SendBuffer(u8g2);
	}
}

//圆形测试
void DrawCircle(u8g2_t *u8g2)
{
	for(int i=0;i<32;i=i+2)
	{
		u8g2_ClearBuffer(u8g2); 
			   	
		u8g2_DrawCircle(u8g2,32,32,i,U8G2_DRAW_ALL);//画圆
		u8g2_DrawCircle(u8g2,64,32,i,U8G2_DRAW_ALL);
		u8g2_DrawCircle(u8g2,96,32,i,U8G2_DRAW_ALL);
		
		u8g2_SendBuffer(u8g2);
	}
}


//椭圆形测试
void DrawEllipse(u8g2_t *u8g2)
{
	for(int i=0;i<32;i=i+2)
	{
		u8g2_ClearBuffer(u8g2); 
		
		u8g2_DrawEllipse(u8g2,32,32,15+i,10,U8G2_DRAW_ALL);//画椭圆
		u8g2_DrawEllipse(u8g2,64,32,15+i,10,U8G2_DRAW_ALL);//
		u8g2_DrawEllipse(u8g2,96,32,15+i,10,U8G2_DRAW_ALL);//
		
		u8g2_DrawEllipse(u8g2,64,16,10,15+i,U8G2_DRAW_ALL);//画椭圆
		u8g2_DrawEllipse(u8g2,64,32,10,15+i,U8G2_DRAW_ALL);//
		u8g2_DrawEllipse(u8g2,64,48,10,15+i,U8G2_DRAW_ALL);//
		
		u8g2_DrawFilledEllipse(u8g2,64,32,15,10,U8G2_DRAW_ALL);//画填充椭圆
		
		u8g2_SendBuffer(u8g2);
	}
}

#if SW_IIC
uint8_t gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
  //printf("%s:msg = %d,arg_int = %d\r\n",__FUNCTION__,msg,arg_int);
  switch(msg) {
    case U8X8_MSG_DELAY_100NANO:		// delay arg_int * 100 nano seconds
      __NOP();
      break;
    case U8X8_MSG_DELAY_10MICRO:		// delay arg_int * 10 micro seconds
 	    for (uint16_t n = 0; n < 320; n++) {
         __NOP();
      }     
      break;
    case U8X8_MSG_DELAY_MILLI:			// delay arg_int * 1 milli second
      HAL_Delay(1);
      break;
    case U8X8_MSG_DELAY_I2C:		    // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
          //delay 5us
          delay_us(5);						// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us

    case U8X8_MSG_GPIO_I2C_CLOCK:		// arg_int=0: Output low at I2C clock pin
      if(arg_int == 1) {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_SET);
      } else if(arg_int == 0) {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);  
      }          
      break;							// arg_int=1: Input dir with pullup high for I2C clock pin
    case U8X8_MSG_GPIO_I2C_DATA:		// arg_int=0: Output low at I2C data pin
      //  printf("U8X8_MSG_GPIO_I2C_DATA:%d\r\n",arg_int);
      if(arg_int == 1)  {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
      } else if(arg_int == 0) {
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);  
      }         
      break;							// arg_int=1: Input dir with pullup high for I2C data pin
    case U8X8_MSG_GPIO_MENU_SELECT:
        u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_NEXT:
        u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_PREV:
        u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_HOME:
        u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);
        break;
    default:
      u8x8_SetGPIOResult(u8x8, 1);		// default return value
      break;
  }
  return 1;
}
#else
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
	static uint8_t buffer[32];		/* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
	static uint8_t buf_idx;
	uint8_t *data;

	switch(msg)
	{
		case U8X8_MSG_BYTE_SEND:
		  data = (uint8_t *)arg_ptr;      
		  while( arg_int > 0 ){
					buffer[buf_idx++] = *data;
					data++;
					arg_int--;
				}      
		break;
				
		case U8X8_MSG_BYTE_INIT:
		  /* add your custom code to init i2c subsystem */
		break;
			
		case U8X8_MSG_BYTE_START_TRANSFER:
		  buf_idx = 0;
		break;
			
		case U8X8_MSG_BYTE_END_TRANSFER:
		HAL_I2C_Master_Transmit(&i2c_test, buffer[0], &buffer[1], buf_idx - 1);
		break;
			
		default:
		  return 0;
	}
	return 1;
}

uint8_t gpio_and_delay(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
{
	switch(msg)
	{
		case U8X8_MSG_GPIO_AND_DELAY_INIT:
			break;
			
		case U8X8_MSG_DELAY_MILLI:
			HAL_Delay(arg_int);
			break;
			
		case U8X8_MSG_GPIO_I2C_CLOCK:		
			break;							
			
		case U8X8_MSG_GPIO_I2C_DATA:			
			break;
			
		default:	
			return 0;
	}
	return 1; // command processed successfully.
}
#endif

void sub_task_fast_blinking(__async__, void* arg) {
    (void)arg;
    while(!g_exit) {
			BSP_LED_Toggle(LED1);
      s_task_msleep(__await__, 50);        /* wait for 50 milliseconds */
    }    
}

void sub_task_set_low(__async__, void* arg) {
    (void)arg;
    while(!g_exit) {
        s_task_sleep(__await__, 3);          /* wait for 3 seconds */
    }
}

void main_task(__async__, void* arg) {
    (void)arg;

    /* create two sub tasks */
    s_task_create(g_stack0, sizeof(g_stack0), sub_task_fast_blinking, NULL);
    // s_task_create(g_stack1, sizeof(g_stack1), sub_task_set_low, NULL);

    /* wait for 10 seconds */
    s_task_sleep(__await__, 10);

    g_exit = true;

    /* wait two sub tasks return */
    s_task_join(__await__, g_stack0);
    // s_task_join(__await__, g_stack1);
}

/*官方提供的Logo绘制demo*/
void DrawLogo(u8g2_t *u8g2)
{
//    u8g2_SetFontMode(u8g2, 1); /*字体模式选择*/
//    u8g2_SetFontDirection(u8g2, 0); /*字体方向选择*/
//    u8g2_SetFont(u8g2, u8g2_font_inb24_mf); /*字库选择*/  //u8g2_font_inb24_mf
//    u8g2_DrawStr(u8g2, 0, 20, "U");
    
//    u8g2_SetFontDirection(u8g2, 1);
//    u8g2_SetFont(u8g2, u8g2_font_inb30_mn); //u8g2_font_inb30_mn
//    u8g2_DrawStr(u8g2, 21,8,"8");
//        
//    u8g2_SetFontDirection(u8g2, 0);
//    u8g2_SetFont(u8g2, u8g2_font_inb24_mf); //u8g2_font_inb24_mf
//    u8g2_DrawStr(u8g2, 51,30,"g");
//    u8g2_DrawStr(u8g2, 67,30,"\xb2");
    
    u8g2_DrawHLine(u8g2, 2, 35, 47);
    u8g2_DrawHLine(u8g2, 3, 36, 47);
    u8g2_DrawVLine(u8g2, 45, 32, 12);
    u8g2_DrawVLine(u8g2, 46, 33, 12);
  
    u8g2_SetFont(u8g2, u8g2_font_4x6_tr);  //u8g2_font_4x6_tr
    u8g2_DrawStr(u8g2, 1,54,"github.com/olikraus/u8g2");
	
	u8g2_SendBuffer(u8g2);
}

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void) {
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();		
	
  /* Configure the system clock to HIRC 24MHz*/
  SystemClock_Config();
	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();
	__HAL_RCC_GPIOC_CLK_ENABLE();
	__HAL_RCC_GPIOD_CLK_ENABLE();
  /* Initialize BSP Led for LED1 */	
  BSP_LED_Init(LED1);
	
	GPIO_InitTypeDef  gpioi2c={0};
#if SW_IIC
	gpioi2c.Pin    = GPIO_PIN_5;
	gpioi2c.Mode = GPIO_MODE_OUTPUT; // GPIO端口复用功能 
	gpioi2c.OpenDrain = GPIO_OPENDRAIN; // 开漏输出
	gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE; // 禁止输入去抖动
	gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH; // 电压转换速率
	gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH; // 驱动强度
	gpioi2c.Pull = GPIO_PULLUP;			// 上拉
	HAL_GPIO_Init(GPIOB, &gpioi2c);
	
	
	gpioi2c.Pin = GPIO_PIN_4;
	gpioi2c.Mode = GPIO_MODE_OUTPUT;
	gpioi2c.OpenDrain = GPIO_OPENDRAIN; 
	gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
	gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH;
	gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
	gpioi2c.Pull = GPIO_PULLUP;	
	HAL_GPIO_Init(GPIOB, &gpioi2c);
#else
	__HAL_RCC_I2C_CLK_ENABLE();
	gpioi2c.Pin    = GPIO_PIN_5;
	gpioi2c.Mode = GPIO_MODE_AF; // GPIO端口复用功能 
	gpioi2c.Alternate = GPIO_AF4_I2C_SDA;
	gpioi2c.OpenDrain = GPIO_OPENDRAIN; // 开漏输出
	gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE; // 禁止输入去抖动
	gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH; // 电压转换速率
	gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH; // 驱动强度
	gpioi2c.Pull = GPIO_PULLUP;			// 上拉
	HAL_GPIO_Init(GPIOB, &gpioi2c);
	
	
	gpioi2c.Pin = GPIO_PIN_4;
	gpioi2c.Mode = GPIO_MODE_AF;
	gpioi2c.Alternate = GPIO_AF4_I2C_SCL;
	gpioi2c.OpenDrain = GPIO_OPENDRAIN; 
	gpioi2c.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
	gpioi2c.SlewRate = GPIO_SLEW_RATE_HIGH;
	gpioi2c.DrvStrength = GPIO_DRV_STRENGTH_HIGH;
	gpioi2c.Pull = GPIO_PULLUP;	
	HAL_GPIO_Init(GPIOB, &gpioi2c);
	
	i2c_test.Instance = I2C;
	i2c_test.Init.master = I2C_MASTER_MODE_ENABLE; // 主机模式使能
	i2c_test.Init.slave = I2C_SLAVE_MODE_DISABLE; // 从机模式禁止
	i2c_test.Mode = HAL_I2C_MODE_MASTER; // 主机模式
	
	i2c_test.Init.broadack = I2C_BROAD_ACK_DISABLE; // 广播地址应答禁止
	i2c_test.Init.speedclock = I2C_SPEED_RATE; // I2C传输速率  
	i2c_test.State = HAL_I2C_STATE_RESET; //
	
	HAL_I2C_Init(&i2c_test);
#endif
  u8g2_t u8g2; // a structure which will contain all the data for one display
#if SW_IIC
  u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, gpio_and_delay);  // init u8g2 structure
#else
	u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, gpio_and_delay);  // init u8g2 structure
#endif
  u8g2_InitDisplay(&u8g2); // send init sequence to the display, display is in sleep mode after this,
  u8g2_SetPowerSave(&u8g2, 0); // wake up display
	
  /* Configure uart1 for printf */	
//  LogInit();	
//  printf("LED toggle every 1 second\n");
    s_task_init_system();
    main_task(__await__, NULL);
		
		DrawLogo(&u8g2);
		DrawProcess(&u8g2);
	int t;
  while (1)
  {
		HAL_Delay(1000);
		u8g2_ClearBuffer(&u8g2); 
		if(++t >= 32) t = 1;
		u8g2_DrawCircle(&u8g2,64,32,t,U8G2_DRAW_ALL);
		u8g2_DrawCircle(&u8g2,32,32,t,U8G2_DRAW_ALL);
		u8g2_DrawCircle(&u8g2,96,32,t,U8G2_DRAW_ALL);
		u8g2_SendBuffer(&u8g2); 
  }
}



/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
	
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};	
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HIRC;
  RCC_OscInitStruct.HIRCState = RCC_HIRC_ON;
  RCC_OscInitStruct.HIRCCalibrationValue = RCC_HIRCCALIBRATION_24M;

  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
	
  /**Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HIRC;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APBCLKDivider = RCC_PCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }	
}
 


/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */


/* Private function -------------------------------------------------------*/



